# Galactic Harmonic Module.
from mayan_cal import GALACTIC_CONSTANT, NUMERICAL_BASE, HIGHEST_TONE
from mayan_cal import gregarian_date, checkGregarianDate
from mayan_cal.structure import Tribe, Tone

def digit_order():
    # Returns a list of digits sorted corresponding to the Tribe numbers.
    tribes = Tribe.index.keys()
    tribes = filter(lambda n:type(n) is int, tribes)
    tribes.sort()

    for t in tribes:
        yield Tribe.index[t].digit


# Todo: Complete conversion algorithm.

# This conversion chart was generated by print_year_conversion().
year_conversion_chart = {1997: 257, 1949: 257, 2001: 257,
                         1902:   2, 1954:   2, 2006:   2,
                         1876: 132, 1928: 132, 1980: 132,
                         1907:   7, 1959:   7, 2011:   7,
                         1881: 137, 1933: 137, 1985: 137,
                         1860:  12, 1912:  12, 1964:  12,
                         1886: 142, 1938: 142, 1990: 142,
                         1865:  17, 1917:  17, 1969:  17,
                         1891: 147, 1943: 147, 1995: 147,
                         1870:  22, 1922:  22, 1974:  22,
                         1896: 152, 1948: 152, 2000: 152,
                         1875:  27, 1927:  27, 1979:  27,
                         1901: 157, 1953: 157, 2005: 157,
                         1880:  32, 1932:  32, 1984:  32,
                         1906: 162, 1958: 162, 2010: 162,
                         1885:  37, 1937:  37, 1989:  37,
                         1859: 167, 1911: 167, 1963: 167,
                         1890:  42, 1942:  42, 1994:  42,
                         1864: 172, 1916: 172, 1968: 172,
                         1895:  47, 1947:  47, 1999:  47,
                         1869: 177, 1921: 177, 1973: 177,
                         1900:  52, 1952:  52, 2004:  52,
                         1874: 182, 1926: 182, 1978: 182,
                         1905:  57, 1957:  57, 2009:  57,
                         1879: 187, 1931: 187, 1983: 187,
                         1858:  62, 1910:  62, 1962:  62,
                         1884: 192, 1936: 192, 1988: 192,
                         1863:  67, 1915:  67, 1967:  67,
                         1889: 197, 1941: 197, 1993: 197,
                         1868:  72, 1920:  72, 1972:  72,
                         1894: 202, 1946: 202, 1998: 202,
                         1873:  77, 1925:  77, 1977:  77,
                         1899: 207, 1951: 207, 2003: 207,
                         1878:  82, 1930:  82, 1982:  82,
                         1904: 212, 1956: 212, 2008: 212,
                         1883:  87, 1935:  87, 1987:  87,
                         1909: 217, 1961: 217, 2013: 217,
                         1888:  92, 1940:  92, 1992:  92,
                         1862: 222, 1914: 222, 1966: 222,
                         1893:  97, 1945:  97, 1997:  97,
                         1867: 227, 1919: 227, 1971: 227,
                         1898: 102, 1950: 102, 2002: 102,
                         1872: 232, 1924: 232, 1976: 232,
                         1903: 107, 1955: 107, 2007: 107,
                         1877: 237, 1929: 237, 1981: 237,
                         1908: 112, 1960: 112, 2012: 112,
                         1882: 242, 1934: 242, 1986: 242,
                         1861: 117, 1913: 117, 1965: 117,
                         1887: 247, 1939: 247, 1991: 247,
                         1866: 122, 1918: 122, 1970: 122,
                         1992: 252, 1944: 252, 1996: 252,
                         1871: 127, 1923: 127, 1975: 127}

conversion_to_year = {
  # 2, 7 are wrapped around below.
  #       3   -1
  #   1       -2
  # 0         -1
  #     2     +2
  #         4 +2

  # 10
   12:                         [1860, 1912, 1964],
   17:                         [1865, 1917, 1969],
   22:                         [1870, 1922, 1974],
   27:                         [1875, 1927, 1979],
   32:                         [1880, 1932, 1984],
   37:                         [1885, 1937, 1989],
   42:                         [1890, 1942, 1994],
   47:                         [1895, 1947, 1999],
   52:                         [1900, 1952, 2004],
   57:                         [1905, 1957, 2009],

  # 10
   62:                   [1858, 1910, 1962],
   67:                   [1863, 1915, 1967],
   72:                   [1868, 1920, 1972],
   77:                   [1873, 1925, 1977],
   82:                   [1878, 1930, 1982],
   87:                   [1883, 1935, 1987],
   92:                   [1888, 1940, 1992],
   97:                   [1893, 1945, 1997],
  102:                   [1898, 1950, 2002],
  107:                   [1903, 1955, 2007],
  112:                   [1908, 1960, 2012],

  # 10
  117:             [1861, 1913, 1965],
  122:             [1866, 1918, 1970],
  127:             [1871, 1923, 1975],
  132:             [1876, 1928, 1980],
  137:             [1881, 1933, 1985],
  142:             [1886, 1938, 1990],
  147:             [1891, 1943, 1995],
  152:             [1896, 1948, 2000],
  157:             [1901, 1953, 2005],
  162:             [1906, 1958, 2010],

  # 11
  167:       [1859, 1911, 1963],
  172:       [1864, 1916, 1968],
  177:       [1869, 1921, 1973],
  182:       [1874, 1926, 1978],
  187:       [1879, 1931, 1983],
  192:       [1884, 1936, 1988],
  197:       [1889, 1941, 1993],
  202:       [1894, 1946, 1998],
  207:       [1899, 1951, 2003],
  212:       [1904, 1956, 2008],
  217:       [1909, 1961, 2013],

  222: [1862, 1914, 1966],
  227: [1867, 1919, 1971],
  232: [1872, 1924, 1976],
  237: [1877, 1929, 1981],
  242: [1882, 1934, 1986],
  247: [1887, 1939, 1991],
  252: [1992, 1944, 1996],
  257: [1997, 1949, 2001],
    2: [1902, 1954, 2006],
    7: [1907, 1959, 2011],
  }

# !! Make sure important files aren't overwritten with this naming scheme !!
YEAR_CONVERSION_CHART_VARIABLE_NAME = 'year_conversion_chart'
YEAR_CONVERSION_CHART_FILENAME = 'mayan_cal/%s.py' % (YEAR_CONVERSION_CHART_VARIABLE_NAME)

def calculate_year_conversion():
    chart = globals()[YEAR_CONVERSION_CHART_VARIABLE_NAME] = dict()
    for (c, s) in conversion_to_year.iteritems():
        for y in s:
            chart[y] = c

calculate_year_conversion()

def print_year_conversion(stream = None, variable_name = YEAR_CONVERSION_CHART_VARIABLE_NAME):
    # Initialize stream.
    if stream is None:
        stream = open(YEAR_CONVERSION_CHART_FILENAME, 'w')

    # Create a tab constant.
    tab = len(variable_name) + len(' = {')
    tab = ' ' * tab

    # Print variable assignment header.
    w = stream.write
    w(variable_name)
    w(' = {')

    items = conversion_to_year.items()
    p = len(items)
    pSub1 = p - 1

    # Iterate items and years tracking indices and upper bounds.
    for i in xrange(0, p):
        c, s = items[i]

        x = len(s)
        xSub1 = x - 1
        for y in xrange(0, x):
            if y == 0 and i != 0:
                w(tab)

            # Write formatted entry.
            w('%d: %3d' % (s[y], c))

            # Write line/section terminators.
            if i == pSub1:
                w(y == xSub1 and '}\n' or ', ')
            else:
                w(y == xSub1 and ',\n' or ', ')


# There is no need to extrapolate for other gregarian months, so this
# will remain a static chart.
month_conversion_chart = {1:    0,        2:   31,        3:   59,
                          4:   90,        5:  120,        6:  151,
                          7:  181,        8:  212,        9:  243,
                          10:  13,        11:  44,        12:  74}

def get_year_conversion(year):
    # Every 52 years, three years converge on the same conversion number.
    # For decades > 1900, year - 1900 + 52 = conversion number.

    assert year in year_conversion_chart, ValueError(year)
    return year_conversion_chart[year]

def get_month_conversion(month):
    assert month in month_conversion_chart, ValueError(month)
    return month_conversion_chart[month]

def get_kin_number(day):
    checkGregarianDate(day)
    assert type(day) is gregarian_date, TypeError(type(day).__name__)

    total = get_year_conversion(day.year) + get_month_conversion(day.month) + day.day
    assert total >= 0, ValueError('Conversion algorithm yielded negative value! (%d)' % total)
    if total < GALACTIC_CONSTANT:
        return total

    return total - GALACTIC_CONSTANT

def get_tribe_tone(day):
    kin = get_kin_number(day)

    tribe = Tribe.index[kin % NUMERICAL_BASE]
    tone  = Tone.index[(kin % HIGHEST_TONE) or HIGHEST_TONE]

    return tribe, tone

def get_guiding_power(kin_number):
    # The guiding power rotates with each mayan day from the seed
    # for each tribe and then repeating.  The day must be converted
    # to a 260-day mayan calendar date first.

    pass

class GuidingPowerFile(list):
    # Converts a file to a list of Tribes representing their power.
    def __init__(self, filename):
        self.start_date = None
        list.__init__(self, self.parse(filename))

    def parse(self, filename):
        gaps = []
        for line in open(filename):
            commentpos = line.find('#')
            if commentpos >= 0:
                line = line[:commentpos]

            line = line.strip()
            if not line:
                continue

            if line[0] == '[':
                assert line[-1] == ']'
                date = self.parse_datestring(line[1:-1])

                # Detect gaps
                # Determinate start_date

            else:
                tribe = self.power_index[line.lower()]
                # validate
                yield tribe

            # verify against gaps

    def parse_datestring(self, datestring):
        pass

    power_index = dict((tribe.power, tribe.number)
                       for tribe in Tribe.index.itervalues()
                       if isinstance(tribe, Tribe))

def analyze_guiding_powers(filename):
    guiding_powers = GuidingPowerFile(filename)
    return guiding_powers
